#include <iostream>
#include <memory>

class Fruit
{
public:
    virtual void show() = 0;
};
class Apple : public Fruit
{
public:
    void show() override
    {
        std::cout << "This is an apple." << std::endl;
    }
};
class Banana : public Fruit
{
public:
    void show() override
    {
        std::cout << "This is a banana." << std::endl;
    }
};

// 1. 简单工厂模式
// class FruitFactory
// {
// public:
//     using ptr = std::shared_ptr<Fruit>;

//     static ptr createFruit(const std::string& name)
//     {
//         if (name == "apple")
//         {
//             return ptr(new Apple());
//         }
//         else if (name == "banana")
//         {
//             return ptr(new Banana());
//         }
//         else
//         {
//             return nullptr;
//         }
//     }
// };
// void test1()
// {
//     FruitFactory::ptr apple = FruitFactory::createFruit("apple");
//     apple->show();

//     FruitFactory::ptr banana = FruitFactory::createFruit("banana");
//     banana->show();

//     FruitFactory::ptr orange = FruitFactory::createFruit("orange");
//     if (orange)
//     {
//         orange->show();
//     }
//     else
//     {
//         std::cout << "No such fruit." << std::endl;
//     }
// }

// 2. 工厂方法模式 -- 符合开闭原则
// class FruitFactory
// {
// public:
//     using Fruitptr = std::shared_ptr<Fruit>;

//     virtual Fruitptr createFruit(const std::string& name) = 0;
// };
// class AppleFactory : public FruitFactory
// {
// public:
//     Fruitptr createFruit(const std::string& name) override
//     {
//         if (name == "apple")
//         {
//             return Fruitptr(new Apple());
//         }
//         else
//         {
//             return nullptr;
//         }
//     }
// };
// class BananaFactory : public FruitFactory
// {
// public:
//     Fruitptr createFruit(const std::string& name) override
//     {
//         if (name == "banana")
//         {
//             return Fruitptr(new Banana());
//         }
//         else
//         {
//             return nullptr;
//         }
//     }
// };
// void test2()
// {
//     std::shared_ptr<FruitFactory> fac = std::make_shared<AppleFactory>();
//     std::shared_ptr<Fruit> fruit = fac->createFruit("apple");
//     fruit->show();

//     fac.reset(new BananaFactory());
//     fruit = fac->createFruit("banana");
//     fruit->show();
// }

// 3. 抽象工厂模式 -- 违背开闭原则
class Animal
{
public:
    virtual void show() = 0;
};
class Dog : public Animal
{
public:
    void show() override
    {
        std::cout << "This is a dog." << std::endl;
    }
};
class Cat : public Animal
{
public:
    void show() override
    {
        std::cout << "This is a cat." << std::endl;
    }
};

class Factory
{
public:
    virtual std::shared_ptr<Animal> createAnimal(const std::string& name) = 0;
    virtual std::shared_ptr<Fruit> createFruit(const std::string& name) = 0;
};
class AnimalFactory : public Factory
{
public:
    std::shared_ptr<Animal> createAnimal(const std::string& name) override
    {
        if (name == "dog")
        {
            return std::shared_ptr<Animal>(new Dog());
        }
        else if (name == "cat")
        {
            return std::shared_ptr<Animal>(new Cat());
        }
        else
        {
            return nullptr;
        }
    }
    std::shared_ptr<Fruit> createFruit(const std::string& name) override
    {
        return nullptr;
    }
};

class FruitFactory : public Factory
{
public:
    std::shared_ptr<Animal> createAnimal(const std::string& name) override
    {
        return nullptr;
    }
    std::shared_ptr<Fruit> createFruit(const std::string& name) override
    {
        if (name == "apple")
        {
            return std::shared_ptr<Fruit>(new Apple());
        }
        else if (name == "banana")
        {
            return std::shared_ptr<Fruit>(new Banana());
        }
        else
        {
            return nullptr;
        }
    }
};

class FactoryProducer
{
public:
    static std::shared_ptr<Factory> createFactory(const std::string& name)
    {
        if (name == "animal")
        {
            return std::shared_ptr<Factory>(new AnimalFactory());
        }
        else if (name == "fruit")
        {
            return std::shared_ptr<Factory>(new FruitFactory());
        }
        else
        {
            return nullptr;
        }
    }
};
void test3()
{
    std::shared_ptr<Factory> fac = FactoryProducer::createFactory("animal");
    std::shared_ptr<Animal> animal = fac->createAnimal("dog");
    animal->show();
    animal = fac->createAnimal("cat");
    animal->show();

    fac = FactoryProducer::createFactory("fruit");
    std::shared_ptr<Fruit> fruit = fac->createFruit("apple");
    fruit->show();
    fruit = fac->createFruit("banana");
    fruit->show();
}


int main()
{
    //test1();
    //test2();
    test3();
    return 0;
}